home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / routes.c < prev    next >
C/C++ Source or Header  |  1996-07-19  |  11KB  |  482 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <netdb.h>
  5. #include "netconf.h"
  6. #include "../paths.h"
  7. #include "../xconf/xconf.h"
  8. #include "netconf.m"
  9.  
  10. extern CONFIG_FILE f_conf_routes;
  11.  
  12. /*
  13.     Parse the argument of a route add command (read from ETC_CONF_ROUTES
  14.     Return -1 if any error.
  15. */
  16. static int route_parsecmd (
  17.     const char *buf,
  18.     int noline,
  19.     SSTRING &ip_dst,
  20.     SSTRING &gateway,
  21.     SSTRING &netmask,
  22.     SSTRING &flags)
  23. {
  24.     int ret = 0;
  25.     char words[8][100];
  26.     netmask.setfrom("");
  27.     words[0][0] = words[1][0] = words[2][0] = words[3][0] = '\0';
  28.     words[4][0] = words[5][0] = words[6][0] = words[7][0] = '\0';
  29.     sscanf (buf,"%s %s %s %s %s %s %s %s"
  30.         ,words[0],words[1],words[2],words[3]
  31.         ,words[4],words[5],words[6],words[7]);
  32.     int i=0;
  33.     int seen_host = 0;
  34.     if (strcmp(words[0],"-net")==0){
  35.         flags.setfrom ("UG");
  36.         i++;
  37.     }else if (strcmp(words[0],"-host")==0){
  38.         flags.setfrom ("UGH");
  39.         seen_host = 1;
  40.         i++;
  41.     }else{
  42.         flags.setfrom ("UG");
  43.     }
  44.     if (strcmp(words[i],"default")==0
  45.         || device_validip(words[i],seen_host)){
  46.         ip_dst.setfrom (words[i]);
  47.     }else{
  48.         struct netent *ent = getnetbyname (words[i]);
  49.         if (ent == NULL){
  50.             xconf_error (MSG_U(E_IVLDEST
  51.                 ,"Invalid destination %s for line %d in file %s\n%s\n")
  52.                 ,words[i],noline,ETC_CONF_ROUTES,buf);
  53.             ret = -1;
  54.         }else{
  55.             devices_ip2a(ent,ip_dst);
  56.         }
  57.     }
  58.     i++;
  59.     if (strcmp(words[i],"gw")!=0){
  60.         xconf_error (MSG_U(E_NOKEYGW
  61.             ,"Keyword gw missing from line %d of file %s\n%s")
  62.             ,noline,ETC_CONF_ROUTES,buf);
  63.         ret = -1;
  64.     }else{
  65.         i++;
  66.         if (device_validip(words[i],1)){
  67.             gateway.setfrom (words[i]);
  68.         }else{
  69.             struct hostent *ent = gethostbyname (words[i]);
  70.             if (ent == NULL){
  71.                 xconf_error (MSG_U(E_IVLGTW
  72.                     ,"Invalid gateway %s for line %d in file %s\n%s\n")
  73.                     ,words[i],noline,ETC_CONF_ROUTES,buf);
  74.                 ret = -1;
  75.             }else{
  76.                 devices_ip2a (ent,gateway);
  77.             }
  78.         }
  79.         i++;
  80.     }
  81.     if (words[i][0] != '\0'){
  82.         if (strcmp(words[i],"netmask")!=0){
  83.             xconf_error (MSG_U(E_NETMASK
  84.                 ,"Keyword netmask expected, on line %d of file %s\n%s")
  85.                 ,noline,ETC_CONF_ROUTES,buf);
  86.             ret = -1;
  87.         }else{
  88.             i++;
  89.             netmask.setfrom (words[i]);
  90.         }
  91.     }
  92.     return ret;
  93. }
  94.  
  95. /*
  96.     Reformat a command (reverse route_parsecmd)
  97. */
  98. static void route_formatcmd(
  99.     const SSTRING &ip_dst,
  100.     const SSTRING &gateway,
  101.     const SSTRING &netmask,
  102.     const SSTRING &flags,
  103.     char *buf)
  104. {
  105.     buf[0] = '\0';
  106.     if (flags.cmp("UG")==0){
  107.         strcat (buf,"-net ");
  108.     }else{
  109.         strcat (buf,"-host ");
  110.     }
  111.     buf += strlen(buf);
  112.     buf += sprintf(buf,"%s gw %s",ip_dst.get(),gateway.get());
  113.     if (!netmask.is_empty()){
  114.         sprintf (buf," netmask %s",netmask.get());
  115.     }
  116. }
  117.  
  118. /*
  119.     Control a route in the kernel
  120. */
  121. PUBLIC ROUTE::ROUTE (
  122.     const char *dst,
  123.     const char *gate,
  124.     const char *mask,
  125.     const char *_flags,
  126.     const char *_iface)
  127. {
  128.     ip_dst.setfrom (dst);
  129.     ip_gateway.setfrom (gate);
  130.     netmask.setfrom (mask);
  131.     flags.setfrom (_flags);
  132.     iface.setfrom (_iface);
  133.     tag = 0;
  134. }
  135. PUBLIC ROUTE::ROUTE (
  136.     const char *buf,
  137.     int noline)            // Help generate error message
  138. {
  139.     if (route_parsecmd(buf,noline,ip_dst,ip_gateway,netmask,flags)==-1){
  140.         invalid_line.setfrom (buf);
  141.     }
  142.     tag = 0;
  143. }
  144. PUBLIC ROUTE::ROUTE ()
  145. {
  146.     tag = 0;
  147. }
  148.  
  149. PUBLIC ROUTE::~ROUTE ()
  150. {
  151. }
  152. /*
  153.     Format and output in a file like ETC_CONF_ROUTE
  154.     Output a line only if it contain either a valid info or an
  155.     invalid (unparsable) line. So it does not generate empty line.
  156. */
  157. PUBLIC void ROUTE::write (FILE *fout)
  158. {
  159.     if (!invalid_line.is_empty()){
  160.         fprintf (fout,"%s\n",invalid_line.get());
  161.     }else if (!ip_dst.is_empty()){
  162.         char buf[300];
  163.         route_formatcmd (ip_dst,ip_gateway,netmask,flags,buf);
  164.         fprintf (fout,"%s\n",buf);
  165.     }
  166. }
  167. /*
  168.     Return a flag recorded by settag. This allows an application
  169.     to mark a ROUTE as seen or ok or not ok and later, get the
  170.     flag back. THis flag has no internal use for ROUTE. It is just
  171.     kind enough to store it.
  172. */
  173. PUBLIC int ROUTE::gettag ()
  174. {
  175.     return tag;
  176. }
  177. PUBLIC void ROUTE::settag (int _tag)
  178. {
  179.     tag = _tag;
  180. }
  181. /*
  182.     Return != 0 if this route is simply the route to the localnet
  183.     without any gateway.
  184. */
  185. PUBLIC int ROUTE::isdevice ()
  186. {
  187.     return ip_gateway.cmp("*")==0;
  188. }
  189. /*
  190.     Get the interface (eth0) used for a route
  191. */
  192. PUBLIC const char *ROUTE::getiface ()
  193. {
  194.     return iface.get();
  195. }
  196. /*
  197.     Return the gateway of a route.
  198. */
  199. PUBLIC const char *ROUTE::getgateway()
  200. {
  201.     return isdevice() ? iface.get() : ip_gateway.get();
  202. }
  203. /*
  204.     Return the destination of a route.
  205. */
  206. PUBLIC const char *ROUTE::getdst()
  207. {
  208.     return ip_dst.get();
  209. }
  210. /*
  211.     Return if the destination is a host or a network.
  212.     Return != 0 if it is a host.
  213. */
  214. PUBLIC int ROUTE::dst_is_host()
  215. {
  216.     return flags.strchr('H')!=NULL;
  217. }
  218. /*
  219.     Tell is a route match a destination.
  220.     Return != 0 if true.
  221. */
  222. PUBLIC int ROUTE::match(const SSTRING &dst)
  223. {
  224.     return ip_dst.cmp(dst)==0;
  225. }
  226. /*
  227.     Tell if two routes are the same.
  228.     Return 0 if different destination.
  229.            1 if same destination but different configuration.
  230.            2 if exactly the same.
  231. */
  232. PUBLIC int ROUTE::compare(
  233.     const SSTRING &dst,
  234.     const SSTRING &gateway,
  235.     const SSTRING &o_netmask,    // may be an empty string, in this
  236.                                 // case it match anything
  237.     const SSTRING &o_flags)
  238. {
  239.     int ret = 0;
  240.     if (ip_dst.cmp(dst) == 0){
  241.         ret = 1;
  242.         if (ip_gateway.cmp(gateway)==0
  243.             && (o_netmask.is_empty() || netmask.cmp(o_netmask)==0)
  244.             && flags.cmp(o_flags)==0){
  245.             ret = 2;
  246.         }
  247.     }
  248.     return ret;
  249. }
  250.  
  251. /*
  252.     Delete a route from the kernel routing table.
  253.     Returne -1 if any error.
  254. */
  255. PUBLIC int ROUTE::kill ()
  256. {
  257.     char cmd[100];
  258.     sprintf (cmd,"del %s",ip_dst.get());
  259.     return netconf_system_if ("route",cmd);
  260. }
  261.  
  262. /*
  263.     Indicate if a route define the loopback device
  264. */
  265. PUBLIC int ROUTE::is_loopback()
  266. {
  267.     return ip_dst.cmp("127.0.0.1")==0 && ip_gateway.cmp("*")==0;
  268. }
  269. /*
  270.     Indicate if a route define the default route
  271. */
  272. PUBLIC int ROUTE::is_default()
  273. {
  274.     return ip_dst.cmp("default")==0;
  275. }
  276.  
  277. /*
  278.     read all the routes currently active
  279. */
  280. PUBLIC int ROUTES::readactive ()
  281. {
  282.     FILE *fin = popen ("/sbin/route -n","r");
  283.     int ret = -1;
  284.     if (fin == NULL){
  285.         xconf_error (MSG_U(E_CANTXROUTE
  286.             ,"Can't execute command /sbin/route\n"
  287.              "No way to update the route table\n"));
  288.     }else{
  289.         char buf[300];
  290.         /* #Specification: route / /sbin/route
  291.             netconf use /sbin/route -n to read the route table.
  292.             It read only the first four fields (destination, gateway
  293.             genmask and Flags) are read. The genmask is ignored
  294.         */
  295.         // Skip the first 2 lines
  296.         fgets(buf,sizeof(buf)-1,fin);
  297.         fgets(buf,sizeof(buf)-1,fin);
  298.         while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  299.             char ip_dst[20],ip_gate[20],gen_mask[20],flags[20];
  300.             char junk[20],iface[20];
  301.             if (sscanf (buf,"%s %s %s %s %s %s %s %s",ip_dst,ip_gate
  302.                 ,gen_mask,flags,junk,junk,junk,iface)!=8){
  303.                 xconf_error (MSG_U(E_IVLOUTPUT
  304.                     ,"Invalid output from /sbin/route\n%s\n")
  305.                     ,buf);
  306.             }else{
  307.                 ROUTE *rt = new ROUTE (ip_dst,ip_gate,gen_mask,flags,iface);
  308.                 if (rt != NULL) add (rt);
  309.             }
  310.         }
  311.         pclose (fin);
  312.     }
  313.     return ret;
  314. }
  315. PUBLIC void ROUTES::write (FILE *fout)
  316. {
  317.     for (int i=0; i<getnb(); i++) getitem(i)->write (fout);
  318. }
  319. /*
  320.     Get one ROUTE of the table or NULL
  321. */
  322. PUBLIC ROUTE *ROUTES::getitem(int no) const
  323. {
  324.     return (ROUTE*)ARRAY::getitem(no);
  325. }
  326. /*
  327.     Locate a ROUTE in the routing table.
  328.     Return NULL if it does not exist.
  329. */
  330. PUBLIC ROUTE *ROUTES::find (const SSTRING &ip_dst)
  331. {
  332.     ROUTE *ret = NULL;
  333.     int nb = getnb();
  334.     for (int i=0; i<nb; i++){
  335.         ROUTE *pt = getitem(i);
  336.         if (pt->match(ip_dst)){
  337.             ret = pt;
  338.             break;
  339.         }
  340.     }
  341.     return ret;
  342. }
  343.  
  344. extern NETCONF_HELP_FILE help_routes;
  345. static CONFIG_FILE f_var_run_current (VAR_RUN_ROUTES_CURRENT
  346.     ,help_routes,CONFIGF_MANAGED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
  347. /*
  348.     Read all route info stored in VAR_RUN_ROUTES_CURRENT
  349. */
  350. PUBLIC void ROUTES::readbyme()
  351. {
  352.     FILE *fin = f_var_run_current.fopen("r");
  353.     if (fin != NULL){
  354.         char buf[400];
  355.         int noline = 0;
  356.         while (fgets(buf,sizeof(buf)-1,fin)){
  357.             noline++;
  358.             add (new ROUTE (buf,0));
  359.         }
  360.         fclose (fin);
  361.     }
  362. }
  363. /*
  364.     Store all route set during this session in VAR_RUN_ROUTES_CURRENT
  365. */
  366. PUBLIC void ROUTES::writebyme()
  367. {
  368.     FILE *fout = f_var_run_current.fopen("w");
  369.     if (fout != NULL){
  370.         write (fout);
  371.         fclose (fout);
  372.     }
  373. }
  374.  
  375. /*
  376.     Read the /etc/conf.routes and install/correct all routes.
  377.     New routes are added, current routes are validated and corrected
  378.     if need (deleted, reinstall), and obsolete route are removed.
  379.  
  380.     Return -1 if any error.
  381. */
  382. int route_install ()
  383. {
  384.     int ret = -1;
  385.     /* #Specification: ETC_CONF_ROUTES / optionnal
  386.         The file ETC_CONF_ROUTES is optionnal. It means no extra
  387.         routes (only route to local network) will be set if missing.
  388.     */
  389.     ROUTES active;
  390.     active.readactive();
  391.     ROUTES lasttime;    // List of routes established by this program
  392.                     // during a different session
  393.     lasttime.readbyme();
  394.     ROUTES thistime;    // Routes that will be set or accepted this
  395.                         // time
  396.     FILE *fin = f_conf_routes.fopen ("r");
  397.     if (fin != NULL){
  398.         char buf[300];
  399.         int noline;
  400.         while (fgets_strip (buf,sizeof(buf)-1,fin,&noline)!=NULL){
  401.             /* #Specification: ETC_CONF_ROUTES / format
  402.                 The format of /etc/conf.routes is simply the end
  403.                 of a route command (everything after the add keyword).
  404.  
  405.                 So if you want to install a default route (and want
  406.                 to do so by editing /etc/conf.routes manually, then you
  407.                 write
  408.  
  409.                 -net default gw router
  410.  
  411.                 You only write routes which are not associated to devices.
  412.                 The primary route to the ethernet network is taken
  413.                 care automaticly by netconf. You just place extra routes
  414.                 here.
  415.             */
  416.             SSTRING ip_dst,gateway,netmask,flags;
  417.             if(route_parsecmd (buf,noline,ip_dst,gateway
  418.                 ,netmask,flags) != -1){
  419.                 ROUTE * rt = active.find (ip_dst);
  420.                 int add = 0;
  421.                 if (rt == NULL){
  422.                     add = 1;
  423.                 }else if(lasttime.find(ip_dst)!=NULL){
  424.                     // This route was set by me, check if it has
  425.                     // to be updated
  426.                     rt->settag(1);
  427.                     if (rt->compare (ip_dst,gateway,netmask,flags) != 2){
  428.                         rt->kill();
  429.                         add = 1;
  430.                     }else{
  431.                         // This route is still valid, must be written
  432.                         // back into /var/run/routes.current
  433.                         thistime.add (new ROUTE (buf,0));
  434.                     }
  435.                 }
  436.                 /* #Specification: netconf / update routes
  437.                     netconf will only update a route or delete it if
  438.                     it is not needed any more or is slightly different.
  439.                     This means that you should not see any network
  440.                     problem if you add a new route and run netconf --update
  441.                 */
  442.                 if (add){
  443.                     char cmd[300];
  444.                     sprintf (cmd,"add %s",buf);
  445.                     ret = netconf_system_if ("route",cmd);
  446.                     thistime.add (new ROUTE (buf,0));
  447.                 }
  448.             }
  449.         }
  450.         fclose (fin);
  451.     }
  452.     /* #Specification: netconf / update routes / routed
  453.         netconf kills any route not found any more in ETC_CONF_ROUTES
  454.         This may cause a problem to routed. To avoid it, netconf
  455.         will only kill the routes it have setup itself.
  456.  
  457.         Comments welcome.
  458.     */
  459.     for (int i=0; i<active.getnb(); i++){
  460.         ROUTE *pt = active.getitem(i);
  461.         if (pt->gettag()==0
  462.             && lasttime.find(pt->getdst())!=NULL
  463.             && !pt->isdevice()) pt->kill();
  464.     }
  465.     if (!simul_ison())thistime.writebyme();
  466.     return ret;
  467. }
  468. /*
  469.     Check if a route is active to a destination
  470. */
  471. int route_isactive (
  472.     const char *dest,
  473.     char *gateway)
  474. {
  475.     ROUTES active;
  476.     active.readactive();
  477.     ROUTE *rt = active.find(dest);
  478.     if (rt != NULL) strcpy (gateway,rt->getgateway());
  479.     return rt != NULL;
  480. }
  481.  
  482.